package com.im.project.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.im.common.constant.Constant;
import com.im.common.enums.MessageTypeEnum;
import com.im.common.enums.ResultEnum;
import com.im.common.enums.WsEnum;
import com.im.common.exception.BusinessException;
import com.im.common.util.GenerateIdUtil;
import com.im.project.entity.*;
import com.im.project.entity.dto.BaseQueryDto;
import com.im.project.entity.dto.DealContactApplyDto;
import com.im.project.entity.vo.ContactApplyVo;
import com.im.project.entity.vo.MessageVo;
import com.im.project.entity.vo.UserVo;
import com.im.project.mapper.*;
import com.im.project.rabbitmq.RabbitmqProducer;
import com.im.project.service.ContactApplyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * 申请记录 服务层接口实现类
 *
 * @author yunZhouJiaDI
 */
@Slf4j
@Service
public class ContactApplyServiceImpl extends ServiceImpl<ContactApplyMapper, ContactApply> implements ContactApplyService {

    @Resource
    private ContactApplyMapper contactApplyMapper;

    @Resource
    private ContactMapper contactMapper;

    @Resource
    private ClusterUserMapper clusterUserMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private ChatMapper chatMapper;

    @Resource
    private ChatUserMapper chatUserMapper;

    @Resource
    private ChatMessageMapper chatMessageMapper;

    @Resource
    private RabbitmqProducer rabbitmqProducer;

    @Override
    public Page<ContactApplyVo> queryContactApplyList(BaseQueryDto baseQueryDto) {
        return contactApplyMapper.queryContactApplyList(new Page(baseQueryDto.getPageNum(), baseQueryDto.getPageSize()), StpUtil.getLoginIdAsString());
    }

    @Override
    @Transactional
    public Boolean dealContactApply(DealContactApplyDto dealContactApplyDto) {
        if (!(ResultEnum.AGREED_CONTACT_APPLY_STATUS.getCode() == dealContactApplyDto.getStatus() || dealContactApplyDto.getStatus() == ResultEnum.REJECTED_CONTACT_APPLY_STATUS.getCode())) {
            return false;
        }
        ContactApply contactApply = contactApplyMapper.selectById(dealContactApplyDto.getId());
        if (!contactApply.getReceiveUserId().equalsIgnoreCase(StpUtil.getLoginIdAsString())) {
            return false;
        }
        contactApplyMapper.update(
                new ContactApply().
                        setStatus(dealContactApplyDto.getStatus()).
                        setLastApplyTime(new Date().getTime()),
                new QueryWrapper<ContactApply>().
                        eq("id", dealContactApplyDto.getId()).
                        eq("status", ResultEnum.PEND_CONTACT_APPLY_STATUS.getCode()).
                        eq("receive_user_id", StpUtil.getLoginIdAsString())
        );
        String prefix = contactApply.getContactId().substring(0, 1);
        if (dealContactApplyDto.getStatus() == ResultEnum.AGREED_CONTACT_APPLY_STATUS.getCode()) {
            UserVo applyUser = (UserVo) redisTemplate.opsForValue().get(Constant.RedisConstant.USER + contactApply.getApplyUserId());
            UserVo contactUser = (UserVo) redisTemplate.opsForValue().get(Constant.RedisConstant.USER + contactApply.getContactId());
            UserVo receiveUser = (UserVo) redisTemplate.opsForValue().get(Constant.RedisConstant.USER + contactApply.getReceiveUserId());
            Date date = new Date();
            switch (prefix) {
                case Constant.SystemConstant.USER_PREFIX:
                    String chatId = GenerateIdUtil.generateUserChatId(new String[]{contactApply.getApplyUserId(), contactApply.getReceiveUserId()});
                    ChatMessage chatMessage = new ChatMessage().
                            setChatId(chatId).
                            setMessageId(GenerateIdUtil.generateMessageId()).
                            setMessageType(MessageTypeEnum.ADD.getName()).
                            setMessageContent(contactApply.getApplyInfo()).
                            setContactType(ResultEnum.FRIEND_TYPE.getCode()).
                            setSendUserId(applyUser.getUserId()).
                            setSendUsername(applyUser.getUsername()).
                            setSendUserIcon(applyUser.getIcon()).
                            setSendTime(date.getTime()).
                            setContactId(contactUser.getUserId()).
                            setContactUsername(contactUser.getUsername()).
                            setContactUserIcon(contactUser.getIcon());
                    contactMapper.delete(
                            new QueryWrapper<Contact>().
                                    eq("user_id", contactApply.getApplyUserId()).
                                    eq("contact_id", contactApply.getReceiveUserId()).
                                    ne("status", ResultEnum.FRIEND_CONTACT_STATUS.getCode())
                    );
                    contactMapper.delete(
                            new QueryWrapper<Contact>().
                                    eq("user_id", contactApply.getReceiveUserId()).
                                    eq("contact_id", contactApply.getApplyUserId()).
                                    ne("status", ResultEnum.FRIEND_CONTACT_STATUS.getCode())
                    );
                    contactMapper.insert(
                            new Contact().
                                    setUserId(contactApply.getApplyUserId()).
                                    setContactId(contactApply.getContactId()).
                                    setCreateTime(new Date()).
                                    setStatus(ResultEnum.FRIEND_CONTACT_STATUS.getCode()).
                                    setLastUpdateTime(new Date())
                    );
                    redisTemplate.opsForList().leftPush(Constant.RedisConstant.USER_CONTACT + contactApply.getApplyUserId(), contactApply.getContactId());
                    contactMapper.insert(
                            new Contact().
                                    setUserId(contactApply.getContactId()).
                                    setContactId(contactApply.getApplyUserId()).
                                    setCreateTime(new Date()).
                                    setStatus(ResultEnum.FRIEND_CONTACT_STATUS.getCode()).
                                    setLastUpdateTime(new Date())
                    );
                    redisTemplate.opsForList().leftPush(Constant.RedisConstant.USER_CONTACT + contactApply.getContactId(), contactApply.getApplyUserId());
                    chatMapper.delete(new QueryWrapper<Chat>().eq("chat_id", chatId));
                    chatUserMapper.delete(
                            new QueryWrapper<ChatUser>().
                                    eq("chat_id", chatId).
                                    eq("user_id", applyUser.getUserId()).
                                    eq("contact_id", receiveUser.getUserId())
                    );
                    chatUserMapper.delete(
                            new QueryWrapper<ChatUser>().
                                    eq("chat_id", chatId).
                                    eq("user_id", receiveUser.getUserId()).
                                    eq("contact_id", applyUser.getUserId())
                    );
                    chatMapper.insert(
                            new Chat().
                                    setChatId(chatId).
                                    setLastMessage(contactApply.getApplyInfo()).
                                    setLastReceiveTime(date.getTime())
                    );
                    chatUserMapper.insert(
                            new ChatUser().
                                    setChatId(chatId).
                                    setUserId(applyUser.getUserId()).
                                    setContactId(receiveUser.getUserId()).
                                    setContactName(receiveUser.getUsername())
                    );
                    chatUserMapper.insert(
                            new ChatUser().
                                    setChatId(chatId).
                                    setUserId(receiveUser.getUserId()).
                                    setContactId(applyUser.getUserId()).
                                    setContactName(applyUser.getUsername())
                    );
                    chatMessageMapper.insert(chatMessage);
                    rabbitmqProducer.sendMessageProducer(
                            Constant.RabbitmqConstant.ROUTING_KEY + Constant.RabbitmqConstant.SEND_MESSAGE,
                            new MessageVo<ChatMessage>().
                                    setCommandCode(WsEnum.ADD_FRIEND.getCode()).
                                    setCommandName(WsEnum.ADD_FRIEND.getMessage()).
                                    setContactId(contactApply.getApplyUserId()).
                                    setData(chatMessage)
                    );
                    rabbitmqProducer.sendMessageProducer(
                            Constant.RabbitmqConstant.ROUTING_KEY + Constant.RabbitmqConstant.SEND_MESSAGE,
                            new MessageVo<ChatMessage>().
                                    setCommandCode(WsEnum.ADD_FRIEND_SELF.getCode()).
                                    setCommandName(WsEnum.ADD_FRIEND_SELF.getMessage()).
                                    setContactId(contactApply.getContactId()).
                                    setData(chatMessage)
                    );
                    break;
                case Constant.SystemConstant.CLUSTER_PREFIX:
                    Cluster cluster = (Cluster) redisTemplate.opsForValue().get(Constant.RedisConstant.CLUSTER + contactApply.getContactId());
                    if (cluster.getStatus() == ResultEnum.CLUSTER_DISSOLUTION.getCode()) {
                        throw new BusinessException(ResultEnum.CLUSTER_DISSOLUTION.getCode(), ResultEnum.CLUSTER_DISSOLUTION.getMessage());
                    }
                    String clusterChatId = GenerateIdUtil.generateClusterChatId(contactApply.getContactId());
                    ChatMessage clusterChatMessage = new ChatMessage().
                            setChatId(clusterChatId).
                            setMessageId(GenerateIdUtil.generateMessageId()).
                            setMessageType(MessageTypeEnum.COMMON.getName()).
                            setMessageContent(String.format(Constant.SystemConstant.ADD_CLUSTER, '`' + applyUser.getUsername() + '`' + " ")).
                            setContactType(ResultEnum.CLUSTER_TYPE.getCode()).
                            setSendUserId(applyUser.getUserId()).
                            setSendUsername(applyUser.getUsername()).
                            setSendUserIcon(applyUser.getIcon()).
                            setSendTime(date.getTime()).
                            setContactId(cluster.getClusterId()).
                            setContactUsername(cluster.getName()).
                            setContactUserIcon(cluster.getIcon());
                    clusterUserMapper.insert(
                            new ClusterUser().
                                    setClusterId(contactApply.getContactId()).
                                    setUserId(contactApply.getApplyUserId()).
                                    setRole(ResultEnum.ORDINARY_MEMBERS.getCode()).
                                    setCreateTime(date)
                    );
                    redisTemplate.opsForList().leftPush(Constant.RedisConstant.CLUSTER_USER + contactApply.getContactId(), contactApply.getApplyUserId());
                    chatMapper.update(
                            new Chat().setLastReceiveTime(date.getTime()).setLastSendName("").setLastMessage(String.format(Constant.SystemConstant.ADD_CLUSTER, '`' + applyUser.getUsername() + '`' + " ")),
                            new QueryWrapper<Chat>().eq("chat_id", clusterChatId)
                    );
                    ChatUser chatUser = chatUserMapper.selectOne(new QueryWrapper<ChatUser>().eq("user_id", contactApply.getApplyUserId()).eq("contact_id", contactApply.getContactId()));
                    if (ObjectUtils.isEmpty(chatUser)) {
                        chatUserMapper.insert(
                                new ChatUser().
                                        setChatId(clusterChatId).
                                        setUserId(applyUser.getUserId()).
                                        setContactId(contactApply.getContactId()).
                                        setContactName(cluster.getName())
                        );
                    } else {
                        chatUserMapper.updateById(
                                chatUser.
                                        setChatId(clusterChatId).
                                        setUserId(applyUser.getUserId()).
                                        setContactId(contactApply.getContactId()).
                                        setContactName(cluster.getName())
                        );
                    }
                    chatMessageMapper.insert(clusterChatMessage);
                    List<String> contactIdList = redisTemplate.opsForList().range(Constant.RedisConstant.CLUSTER_USER + cluster.getClusterId(), 0, -1);
                    clusterChatMessage.setMemberCount(contactIdList.size());
                    contactIdList.forEach(contactId -> {
                        rabbitmqProducer.sendMessageProducer(
                                Constant.RabbitmqConstant.ROUTING_KEY + Constant.RabbitmqConstant.SEND_MESSAGE,
                                new MessageVo<ChatMessage>().
                                        setCommandCode(WsEnum.ADD_FRIEND.getCode()).
                                        setCommandName(WsEnum.ADD_FRIEND.getMessage()).
                                        setContactId(contactId).
                                        setData(clusterChatMessage)
                        );
                    });
                    break;
            }
        }
        return true;
    }

    @Override
    public Boolean deleteContactApply(Long id) {
        ContactApply contactApply = contactApplyMapper.selectById(id);
        if (contactApply.getApplyUserId().equalsIgnoreCase(StpUtil.getLoginIdAsString())) {
            contactApply.setApplyDelete(ResultEnum.DELETE.getCode());
        } else if (contactApply.getReceiveUserId().equalsIgnoreCase(StpUtil.getLoginIdAsString())) {
            contactApply.setReceiveDelete(ResultEnum.DELETE.getCode());
        }
        contactApplyMapper.updateById(contactApply);
        return true;
    }

}
